#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtGui>
#include <QFile>
#include <QDataStream>
#include <QByteArray>
#include <QTextStream>
#include "./des/DesOne.h"
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //设置擦除的地址只能输入以16进制的方式
    QRegExp regx("[0-9a-fA-F][Xx0-9a-fA-F][0-9a-fA-F]{8}");
    QValidator *validator = new QRegExpValidator(regx, ui->lineEditEraseAddress );
    ui->lineEditEraseAddress->setValidator(validator);

    //设置加密的地址只能输入以16进制的方式
    QValidator *EditAddress = new QRegExpValidator(regx, ui->lineEditAddress );
    ui->lineEditAddress->setValidator(EditAddress);



    //设置密码输入框只可以输入数字且最多为16位
    QRegExp EditKey("[0-9a-fA-F]{16}");
    QValidator *EditKeyValidator = new QRegExpValidator(EditKey, ui->lineEditKey );
    ui->lineEditKey->setValidator(EditKeyValidator);


    //设置数据大小只能为数字（0-9）
    QRegExp EditSize("[0-9]{6}");
    QValidator *EditSizeValidator = new QRegExpValidator(EditSize, ui->lineEditSize );
    ui->lineEditSize->setValidator(EditSizeValidator);

    QValidator *EditEraseSizeValidator = new QRegExpValidator(EditSize, ui->lineEditEraseSize );
    ui->lineEditEraseSize->setValidator(EditEraseSizeValidator);

    //禁止最大化，和最小化
    setWindowFlags(windowFlags() &~ Qt::WindowMinMaxButtonsHint);
}

MainWindow::~MainWindow()
{
    delete ui;
}

//打开Hex文件
void MainWindow::on_pushButtonOpenFile_clicked()
{
    HexPath = QFileDialog::getOpenFileName(this,"打开文件",".","Hex File(*.Hex)");
    ui->lineEditPath->setText(HexPath);
    searchMaxAddress();

}
void MainWindow:: searchMaxAddress()
{
    int maxAddr = 0;        //HEX文件的最大地址
    int segAddr = 0;        //段地址
    int tmpAddr = 0;
    QFile file(HexPath);    //打开Hex文件
    if(file.open(QIODevice::ReadOnly))   //以只读的方式
    {
        QTextStream stream(&file);
        QString line;
        while(!stream.atEnd())
        {
            line = stream.readLine();//读一行数据

            if(line.left(1) == ":") //判断第1字符是否是:
            {
                if (line.mid(1, 8) == "00000001")//数据结束
                {
                    break;
                }

                if(line.mid(7,2) == "02")
                {
                    bool ok;
                    segAddr = line.mid(9,4).toInt(&ok,16);
                    segAddr *=16;
                }
                else if(line.mid(7,2) == "04")
                {
                    bool ok;
                    segAddr = line.mid(9,4).toInt(&ok,16);
                    segAddr <<=16;
                }
                else if(line.mid(7,2) == "00")
                {
                    bool ok;
                    tmpAddr = line.mid(3,4).toInt(&ok,16);//Int32.Parse(szLine.Substring(3, 4), NumberStyles.HexNumber);
                    tmpAddr += line.mid(1,2).toInt(&ok,16);;//UInt16.Parse(szLine.Substring(1, 2), NumberStyles.HexNumber);
                    tmpAddr += segAddr;
                    if (tmpAddr > maxAddr)
                        maxAddr = tmpAddr;
                }
            }
            else
            {
                QMessageBox::critical(this,"Critical",HexPath);
                QMessageBox::critical(this,"错误",("不是标准的HEX文件!"));
            }
        }
    }
    hexMaxAddress = maxAddr & 0x1fffff;  //2M的数据最多
    file.close();
}
//转换
void MainWindow::on_pushButtonTurn_clicked()
{

    if(!checkInputDataLegal())
    {
        return;
    }
    unsigned char data[hexMaxAddress] ;
    createBinFile(HexPath,data);  //创建bin数据

    if(ui->checkBoxEncryp->isChecked())
    {
        bool ok;
        unsigned char key[8] = {0};//{0x73,0xff,0x5d,0x34,0x31,0x43,0x30,0x33};
        QString key_str = ui->lineEditKey->text();
        for(int index_str = 0,index_key = 0; index_key < 8; index_key++)
        {
            key[index_key] = key_str.mid(index_str,2).toInt(&ok,16);
            index_str +=2;
        }

        int addr = hexStringtoHex(ui->lineEditAddress->text());//hex_number.toInt(&ok,16);
        int size = ui->lineEditSize->text().toInt(&ok,10);
        desEncryptionData(addr,size,key,data);

        addr = hexStringtoHex(ui->lineEditEraseAddress->text());//erase_hex_number.toInt(&ok,16);
        size = ui->lineEditEraseSize->text().toInt(&ok,10);
        eraseEncryptionDataSeg(addr,size,data);
        saveBinFile(HexPath.insert(HexPath.length()-4,"Encryption"),data);
        QMessageBox::information(this,"提示","文件加密完成!");

    }
    else
    {
        saveBinFile(HexPath,data);  //转换为Bin文件
        QMessageBox::information(this,"提示","文件转换为BIN完成!");
    }

}
void MainWindow::desEncryptionData(int address,int size,unsigned char *key,unsigned char *data) //加密数据
{
    if(size % 8 != 0)
    {
         QMessageBox::critical(this,"错误","数据长度必须为8的整倍数!");
         return;
    }
    des_one des;
    int addr = address & HEXMAXSIZE;
    unsigned  char key_user[8]= {0};// = {0x73,0xff,0x5d,0x34,0x31,0x43,0x30,0x33};
    unsigned char *out = (unsigned char *)malloc(size);  //size 必须是8的整倍数
    for(int i = 0; i < 8; i++)
    {
        key_user[i] = key[i];
    }

    des.Des_SetKey(key_user);

    //加密数据
    for(int index = 0; index < size / 8; index++)
    {
        des.Des_Run(out + index * 8,data + addr + index * 8,1);
    }

    //写回加密数据
    for(int index = 0; index < 512; index++)
    {
        data[addr+index] = out[index];
    }
    delete[] out;
}

void MainWindow::saveBinFile(QString path,unsigned char *data) //保存文件
{
    QString bin_path = path.replace(path.length() - 3,3,"bin");  //设置bin文件的路径
    QFile bin(bin_path);
    if(bin.open(QIODevice::WriteOnly))
    {
        bin.write((const char *)data,hexMaxAddress);
    }
    bin.close();
}

void MainWindow::eraseEncryptionDataSeg(int address,int size,unsigned char *data)//擦除加密程序
{
    int count = 0;
    if(((address & HEXMAXSIZE) + size) > hexMaxAddress )
    {
        count = hexMaxAddress - (address & HEXMAXSIZE);
    }
    else
    {
        count = size;
    }
    int start_addr = address & HEXMAXSIZE;
    for(int index = 0 ; index < count ;index++ )
    {
        data[ start_addr + index] = 0xFF;
    }
}
void MainWindow::createBinFile(QString path,unsigned char *data) //创建bin文件
{
    int segAddr = 0;
    int i = 0;
    int j = 0;
    QFile file(path);    //打开Hex文件
    if(file.open(QIODevice::ReadOnly))   //以只读的方式
    {
        QTextStream stream(&file);
        QString line;
        while(!stream.atEnd())
        {
            line = stream.readLine();//读一行数据
            if(line.left(1) == ":") //判断第1字符是否是:
            {
                if (line.mid(1, 8) == "00000001")//数据结束
                {
                    break;
                }

                if(line.mid(7,2) == "02")
                {
                    bool ok;
                    segAddr = line.mid(9,4).toInt(&ok,16);
                    segAddr *=16;
                }
                else if(line.mid(7,2) == "04")
                {
                    bool ok;
                    segAddr = line.mid(9,4).toInt(&ok,16);
                    segAddr <<=16;
                }
                else if(line.mid(7,2) == "00")
                {
                    bool ok;
                    int tmpAddr = line.mid(3,4).toInt(&ok,16);//Int32.Parse(szLine.Substring(3, 4), NumberStyles.HexNumber);
                    int num     = line.mid(1,2).toInt(&ok,16);;//UInt16.Parse(szLine.Substring(1, 2), NumberStyles.HexNumber);
                    tmpAddr += (segAddr & 0x1fffff);
                    j = 0;
                    for(i = 0; i < num; i++)
                    {
                        unsigned char x = line.mid(j+9,2).toUShort(&ok,16);
                        data[tmpAddr++] = x;
                        j+=2;
                    }
                }
            }
        }
    }
    file.close();
}
//检验输入是不是合法
bool MainWindow::checkInputDataLegal()
{
    bool ok;
    //路径是不是为空
    if(ui->lineEditPath->text() == "")
    {
        QMessageBox::critical(this,"错误","路径错误!");
        return false;
    }
    //文件的格式是不是为hex
    if((ui->lineEditPath->text().mid(ui->lineEditPath->text().length() - 3,3)).toLower() !="hex")
    {
        QMessageBox::critical(this,"错误","文件格式不对!");
        return false;
    }
    //密码是不是为8个字节
    if(ui->lineEditKey->text().length() != 16)
    {
        QMessageBox::critical(this,"错误","密码必须为16位!");
        return false;
    }
    //加密的数据长度是不是8的整倍数
    if(ui->lineEditSize->text().toInt(&ok,10)%8 != 0)
    {
        QMessageBox::critical(this,"错误","加密数据长度必须为8的整倍数!");
        return false;
    }

    return true;
}
//16进制字符串转16进制数字
int  MainWindow::hexStringtoHex(QString str)
{
    QString hex_number;
    bool ok;
    if(str.mid(0,2) == "0x" ||
       str.mid(0,2) == "0X")
    {
        hex_number = str.mid(2,(str.length() - 2));
    }
    else
    {
        hex_number = str;
    }
    return hex_number.toInt(&ok,16);
}

/*
限制QLineEdit的数值输入范围
http://blog.csdn.net/giselite/article/details/12708031

*/

void MainWindow::on_checkBoxEncryp_stateChanged(int arg1)
{
    if(arg1 == 2)
    {
        ui->pushButtonTurn->setText("加密");
    }
    else if(arg1 == 0)
    {
        ui->pushButtonTurn->setText("转换");
    }
}
